﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Joy.Erp.BasicArchives.Staff;
using Joy.Erp.Ufida.Core;
using Microsoft.Extensions.Logging;
using Volo.Abp;

namespace Joy.Erp.Ufida.Staff
{
    public class OperatorsSyncAppService : UfidaAppService, IOperatorsSyncAppService
    {
        protected IOperatorRepository OperatorRepository => LazyServiceProvider.LazyGetRequiredService<IOperatorRepository>();
        protected IDepartmentRepository DepartmentRepository => LazyServiceProvider.LazyGetRequiredService<IDepartmentRepository>();
        protected IOperatorsUfidaAppService OperatorsUfidaAppService => LazyServiceProvider.LazyGetRequiredService<IOperatorsUfidaAppService>();

        public async Task<AnalysisDto> AnalyzeAsync()
        {
            var analysisDto = new AnalysisDto();
            analysisDto.Id = typeof(Operator).FullName;

            // 获取U9数据的ID列表（去重）
            var u9list = await OperatorsUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.OperatorsID.ToString()).Distinct().ToHashSet();
            analysisDto.U9Count = u9Ids.Count;

            // 使用数据库查询优化，只查询需要的字段
            var pmcQuery = await OperatorRepository.GetQueryableAsync();

            // 获取PMC总数
            analysisDto.Count = await AsyncExecuter.CountAsync(pmcQuery.Where(x => !x.IsDeleted));

            // 获取已同步的SourceKey列表
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 快速计算已同步数量
            analysisDto.AsyncCount = syncedSourceKeys.Count(key => u9Ids.Contains(key));
            analysisDto.UnasyncCount = analysisDto.U9Count - analysisDto.AsyncCount;
            analysisDto.SelfCount = analysisDto.Count - analysisDto.AsyncCount;

            return analysisDto;
        }

        public async Task<List<long>> GetUnasyncIds()
        {
            // 获取U9的所有ID（去重）
            var u9list = await OperatorsUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.OperatorsID).Distinct().ToList();

            // 使用数据库查询，只查询已同步的SourceKey
            var pmcQuery = await OperatorRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            // 使用 HashSet 优化查找性能，时间复杂度从 O(n²) 降到 O(n)
            var syncedSourceKeySet = new HashSet<string>(syncedSourceKeys);

            // 找出未同步的ID
            var unasyncIds = u9Ids
                .Where(id => !syncedSourceKeySet.Contains(id.ToString()))
                .ToList();

            return unasyncIds;
        }

        public async Task<int> CreateByIds‌Async(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return 0;

            // 批量预查询已存在的记录，避免循环查询数据库
            var pmcQuery = await OperatorRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );
            var existingSet = new HashSet<string>(existingSourceKeys);

            // 过滤出需要创建的ID
            var needCreateIds = ids.Where(id => !existingSet.Contains(id.ToString())).ToList();
            if (needCreateIds.Count == 0) return ids.Length;

            var allU9DataDict = new Dictionary<long, List<OperatorsUfidaDto>>();
            foreach (var id in needCreateIds)
            {
                try
                {
                    var items = await OperatorsUfidaAppService.GetItemsAsync(id);
                    if (items != null && items.Count > 0) allU9DataDict[id] = items;
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 获取U9数据失败，Id: {id}");
                }
            }

            if (allU9DataDict.Count == 0) return existingSet.Count;

            var deptSourceKeys = allU9DataDict.Values.Where(items => items.Count > 0).Select(items => items[0].Dept.ToString()).Distinct().ToList();
            var deptCacheDict = await BatchLoadDepartments(deptSourceKeys);

            var entities = new List<Operator>();
            foreach (var kvp in allU9DataDict)
            {
                try
                {
                    var entity = BuildOperatorEntity(kvp.Key, kvp.Value, deptCacheDict);
                    if (entity != null) entities.Add(entity);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 构建实体失败，Id: {kvp.Key}");
                }
            }

            if (entities.Count == 0) return existingSet.Count;

            Logger.LogInformation($"[批量同步-操作员] 开始处理 {entities.Count} 条新增，原有 {existingSet.Count} 条");

            using (var uow = UnitOfWorkManager.Begin(new Volo.Abp.Uow.AbpUnitOfWorkOptions(), requiresNew: true))
            {
                try
                {
                    await OperatorRepository.BulkInsertAsync(entities, autoSave: false);
                    await uow.CompleteAsync();
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 批量创建失败，{ex.Message}");
                    return existingSet.Count;
                }
            }

            Logger.LogInformation($"[批量同步-操作员] 完成！成功创建 {entities.Count} 条，已存在 {existingSet.Count} 条，总计 {entities.Count + existingSet.Count} 条");

            return entities.Count + existingSet.Count;
        }

        public async Task<List<long>> GetSyncedIds()
        {
            var pmcQuery = await OperatorRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );
            return syncedSourceKeys
                .Select(key => long.Parse(key))
                .ToList();
        }

        public async Task<int> UpdateByIdsAsync(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return 0;
            Logger.LogInformation($"[批量同步-操作员] 开始处理 {ids.Length} 条更新");
            var pmcQuery = await OperatorRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingEntities = await AsyncExecuter.ToListAsync(
                pmcQuery.Where(x =>
                    idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );
            if (existingEntities.Count == 0)
            {
                Logger.LogWarning($"[批量同步-操作员] 没有找到需要更新或删除的记录");
                return 0;
            }
            var entityDict = existingEntities.ToDictionary(x => x.SourceKey, x => x);
            var allU9DataDict = new Dictionary<long, List<OperatorsUfidaDto>>();
            foreach (var id in ids)
            {
                if (!entityDict.ContainsKey(id.ToString())) continue;

                try
                {
                    var items = await OperatorsUfidaAppService.GetItemsAsync(id);
                    if (items != null && items.Count > 0)
                        allU9DataDict[id] = items;
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 获取U9数据失败，Id: {id}");
                }
            }

            var deptSourceKeys = allU9DataDict.Values.Where(items => items.Count > 0).Select(items => items[0].Dept.ToString()).Distinct().ToList();
            var deptCacheDict = await BatchLoadDepartments(deptSourceKeys);

            var entitiesToUpdate = new List<Operator>();
            var entitiesToDelete = new List<Operator>();
            foreach (var id in ids)
            {
                try
                {
                    var key = id.ToString();
                    if (!entityDict.TryGetValue(key, out var entity))
                        continue;

                    if (!allU9DataDict.TryGetValue(id, out var u9Items) || u9Items.Count == 0)
                    {
                        entitiesToDelete.Add(entity);
                        continue;
                    }

                    var deptKey = u9Items[0].Dept.ToString();
                    if (!deptCacheDict.TryGetValue(deptKey, out var deptDto))
                    {
                        Logger.LogWarning($"[批量同步-操作员] 未找到部门，SourceKey: {deptKey}");
                        continue;
                    }

                    entity.Code = u9Items[0].Code;
                    entity.Name = u9Items[0].Name;
                    entity.DepartmentId = deptDto.Id;
                    entity.OperatorType = OperatorType.None;
                    foreach (var item in u9Items)
                    {
                        entity.OperatorType |= GetOperatorType(item.OperatorType);
                    }
                    entity.SourceCreatedOn = u9Items
                        .Select(x => x.CreatedOn)
                        .FirstOrDefault(x => x.HasValue);

                    entitiesToUpdate.Add(entity);
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 修改实体失败，Id: {id}");
                }
            }
            if (entitiesToUpdate.Count == 0 && entitiesToDelete.Count == 0)
            {
                Logger.LogInformation($"[批量同步-操作员] 无需更新或删除记录");
                return 0;
            }

            var updateCount = 0;
            var deleteCount = 0;
            using (var uow = UnitOfWorkManager.Begin(new Volo.Abp.Uow.AbpUnitOfWorkOptions(), requiresNew: true))
            {
                try
                {
                    if (entitiesToUpdate.Count > 0)
                    {
                        await OperatorRepository.BulkUpdateAsync(entitiesToUpdate, autoSave: false);
                        updateCount = entitiesToUpdate.Count;
                    }

                    if (entitiesToDelete.Count > 0)
                    {
                        await OperatorRepository.BulkDeleteAsync(entitiesToDelete, autoSave: false);
                        deleteCount = entitiesToDelete.Count;
                    }

                    await uow.CompleteAsync();
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-操作员] 批量更新/删除失败，{ex.Message}");
                }
            }

            Logger.LogInformation($"[批量同步-操作员] 完成！成功更新 {updateCount} 条，删除 {deleteCount} 条");
            return updateCount + deleteCount;
        }

        private OperatorType GetOperatorType(int ufidaOperatorType)
        {
            switch (ufidaOperatorType)
            {
                case 0:
                    return OperatorType.Buyer;
                case 1:
                    return OperatorType.Saler;
                case 2:
                    return OperatorType.Depot;
                case 3:
                    return OperatorType.PickOut;
                case 4:
                    return OperatorType.TallyClerk;
                case 5:
                    return OperatorType.Designer;
                case 6:
                    return OperatorType.Planner;
                case 7:
                    return OperatorType.PruManager;
                case 8:
                    return OperatorType.Stat;
                case 9:
                    return OperatorType.Quality;
                case 10:
                    return OperatorType.PurseBearer;
                case 11:
                    return OperatorType.Receiver;
                case 12:
                    return OperatorType.Asset;
                case 13:
                    return OperatorType.Other;
                case 14:
                    return OperatorType.EqManager;
                default:
                    return OperatorType.None;
            }
        }

        private Operator BuildOperatorEntity(
            long id,
            List<OperatorsUfidaDto> items,
            Dictionary<string, DepartmentDto> deptCacheDict
        )
        {
            if (items == null || items.Count == 0) return null;

            var deptKey = items[0].Dept.ToString();
            if (!deptCacheDict.TryGetValue(deptKey, out var deptDto))
            {
                Logger.LogWarning($"[批量同步-操作员] 未找到部门，SourceKey: {deptKey}");
                return null;
            }

            var entity = new Operator
            {
                SourceType = SourceConfig.SourceType,
                SourceKey = id.ToString(),
                SourceCreatedOn = items[0].CreatedOn,
                Code = items[0].Code,
                Name = items[0].Name,
                DepartmentId = deptDto.Id,
                OperatorType = OperatorType.None,
                Enabled = true,
                TenantId = CurrentTenant.Id,
                CreationTime = Clock.Now,
                CreatorId = CurrentUser.Id,
            };

            foreach (var item in items)
            {
                entity.OperatorType |= GetOperatorType(item.OperatorType);
            }

            entity.SetId(GuidGenerator.Create());
            return entity;
        }

        private async Task<Dictionary<string, DepartmentDto>> BatchLoadDepartments(
            List<string> sourceKeys
        )
        {
            if (sourceKeys == null || sourceKeys.Count == 0)
                return new Dictionary<string, DepartmentDto>();
            var query = await DepartmentRepository.GetQueryableAsync();
            var items = await AsyncExecuter.ToListAsync(
                query.Where(x =>
                    sourceKeys.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );
            return items.ToDictionary(
                x => x.SourceKey,
                x => ObjectMapper.Map<Department, DepartmentDto>(x)
            );
        }

    }
}
